Setting up an ASP.NET Web Client to use IdentityServer via the OpenID Connect protocol

If you haven’t already, follow the installation steps here first.

Table of Contents

  1. Dependencies
  2. Configuring the IdentityServer
  3. Connecting the Client
  4. Adding API Access

Dependencies

  1. .Net 7 SDK
  2. OpenID Connect (support already built into IdentityServer)

Configure the IdentityServer

For this client, we need to configure OIDC in the IdentityServer project.

To enable OIDC in IdentityServer, you need:

  1. An interactive UI
  2. Configuration for OIDC scopes
  3. Configuration for an OIDC client
  4. Users to log in with

If you already have a UI for the IdentityServer, skip this step. Otherwise, use this quickstart command in the src/IdentityServer directory to add the UI to the project:

dotnet new isui

Add support for the standard openid and profile scopes by declaring them in src/IdentityServer/Config.cs:

public static IEnumerable<IdentityResource> IdentityResources =>
  new List<IdentityResource>
  {
    new IdentityResources.OpenId(),
    new IdentityResources.Profile(),
  };

Then register the identity resources in src/IdentityServer/HostingExtensions.cs:

builder.Services.AddIdentityServer()
  .AddInMemoryIdentityResources(Config.IdentityResources)
  .AddInMemoryApiScopes(Config.ApiScopes)
  .AddInMemoryClients(Config.Clients);

If you need to declare test users, the sample UI comes with an in-memory “user db”, with the users ‘alice’ and ‘bob’, whose passwords and usernames match. Enable this by adding in the Service Collection:

builder.Services.AddIdentityServer()
  .AddInMemoryIdentityResources(Config.IdentityResources)
  .AddInMemoryApiScopes(Config.ApiScopes)
  .AddInMemoryClients(Config.Clients)
  .AddTestUsers(TestUsers.Users);

Lastly, register the ASP.NET Core Web App in the Clients list, found in the src/IdentityServer/Config.cs file:

public static IEnumerable<Client> Clients =>
  new List<Client>
  {
    // interactive ASP.NET Core Web App
    new Client
    {
      ClientId = "web",
      ClientSecrets = { new Secret("secret".Sha256()) },

      AllowedGrantTypes = GrantTypes.Code,

      // where to redirect after login
      RedirectUris = { "Web App URI/signin-oidc" },

      // where to redirect after logout
      PostLogoutRedirectUris = {"Web App URI/signout-callback-oidc"},

      AllowedScopes = new List<string>
      {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile
      }
    }
  };

Connecting the Client

If you already have a .NET solution and are connecting the client to the IdentityServer, skip this step. Otherwise, if you are starting with a fresh .NET solution, create a new .NET project in the src directory and add it to the solution:

dotnet new webapp -n WebClient
cd ..
dotnet sln add ./src/WebClient/WebClient.csproj

From the src/WebClient directory, add the OpenID Connect handler pakcage:

dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect

Configure the services in the Program.cs file of the web client:

using System.IdentityModel.Tokens.Jwt;

// ...

JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

builder.Services.AddAuthentication(options =>
  {
    options.DefaultScheme = "Cookies";
    options.DefaultChallengeScheme = "oidc";
  })
  .AddCookie("Cookies")
  .AddOpenIdConnect("oidc", options =>
  {
    options.Authority = "URI of IdentityServer";

    options.ClientId = "web";
    options.ClientSecret = "secret";
    options.ResponseType = "code";

    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.GetClaimsFromUserInfoEndpoint = true;

    options.SaveTokens = true;
  });

Then, add the Authentication to the ASP.NET pipeline in Program.cs:

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

// disable anonymous access for the entire application (if using Razor Pages)
//app.MapRazorPages().RequireAuthorization();

Now everything should be in place to log into the Web Client using OIDC. If you run both the IdentityServer and the WebClient project, then navigate to the Web Client home page, you should redirect to the IdentityServer login page. After logging in, you will be redirected back to the home page of the Web Client.

Adding API Access

In order to add API access to the Web Client, we need to modify the Client in the IdentityServer/Config.cs file as so:

// interactive ASP.NET Core Web App
new Client
{
  ClientId = "web",
  ClientSecrets = { new Secret("secret".Sha256()) },

  AllowedGrantTypes = GrantTypes.Code,

  // where to redirect after login
  RedirectUris = { "Web App URI/signin-oidc" },

  // where to redirect after logout
  PostLogoutRedirectUris = {"Web App URI/signout-callback-oidc"},

  AllowOfflineAccess = true,

  AllowedScopes = new List<string>
  {
    IdentityServerConstants.StandardScopes.OpenId,
    IdentityServerConstants.StandardScopes.Profile,
    "api1"
  }
}

Then, we need to configure the client to ask for access to the API and for a refresh token. In the Web Client Program.cs file, modify the Authentication Service as so:

builder.Services.AddAuthentication(options =>
  {
    options.DefaultScheme = "Cookies";
    options.DefaultChallengeScheme = "oidc";
  })
  .AddCookie("Cookies")
  .AddOpenIdConnect("oidc", options =>
  {
    options.Authority = "URI of IdentityServer";

    options.ClientId = "web";
    options.ClientSecret = "secret";
    options.ResponseType = "code";

    options.SaveTokens = true;

    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("api1");
    options.Scope.Add("offline_access");
    options.GetClaimsFromUserInfoEndpoint = true;
  });

Now if you create a page in the Web App, that requests content from the API, it will be authorized using the access token given from the IdentityServer.